package dxsvalue

import (
	"bufio"
	"encoding/binary"
	"github.com/suiyunonghen/DxCommonLib"
	"io"
	"time"
	"unsafe"
)

type BsonReader struct {
	bfReader *bufio.Reader
}

func NewBsonReader(r io.Reader) BsonReader {
	var result BsonReader
	if bfReader, ok := r.(*bufio.Reader); ok {
		result.bfReader = bfReader
	} else {
		result.bfReader = bufio.NewReader(r)
	}
	return result
}

func (r *BsonReader) Reset(reader io.Reader) {
	if bfReader, ok := reader.(*bufio.Reader); ok {
		r.bfReader = bfReader
	} else {
		r.bfReader = bufio.NewReader(reader)
	}
}

func (r *BsonReader) Decode() (*DxValue, error) {
	c := getCache()
	result, _, err := r.readDocument(c)
	return result, err
}

func (r *BsonReader) readDocument(c *ValueCache) (*DxValue, int, error) {
	b, err := r.bfReader.Peek(4)
	if err != nil {
		return nil, 0, err
	}
	var result *DxValue
	if c == nil {
		result = &DxValue{DataType: VT_Object}
	} else {
		result = c.getValue(VT_Object)
	}
	r.bfReader.Discard(4)
	//文档长度
	docLen := int(binary.LittleEndian.Uint32(b[:4]))
	parseIndex := 4

	var element *DxValue
	var keyName string
	for parseIndex < docLen {
		b, err = r.bfReader.Peek(1)
		if err != nil {
			FreeValue(result)
			return nil, 0, err
		}
		//类型
		bType := BsonType(b[0])
		r.bfReader.Discard(1)
		parseIndex++
		//读取字段cstring,ansic
		//utf8
		keyName, err = r.bfReader.ReadString(0)
		if err != nil {
			FreeValue(result)
			return nil, 0, err
		}
		l := len(keyName)
		parseIndex += l
		keyName = keyName[:l-1] //多了一个0值

		switch bType {
		case BSON_Array:
			element = result.SetKeyCached(keyName, VT_Array, c)
			arrLen, err := r.parseBsonArray(c, element)
			if err != nil {
				return nil, 0, err
			}
			parseIndex += arrLen
		case BSON_EmbeddedDocument:
			element, l, err := r.readDocument(c)
			if err != nil {
				return nil, 0, err
			}
			parseIndex += l
			result.SetKeyValue(keyName, element)
		default:
			element = result.SetKeyCached(keyName, VT_NULL, c)
			vlen, err := r.parseValue(bType, element)
			if err != nil {
				return nil, 0, err
			}
			parseIndex += vlen
		}
		if parseIndex == docLen-1 {
			b, err = r.bfReader.Peek(1)
			if err != nil {
				FreeValue(result)
				return nil, 0, err
			}
			if b[0] == 0 {
				break
			}
		}
	}
	return result, docLen, nil
}

//数组结构解析和文档结构解析差不多，将数组的索引号设定为docment的key
func (r *BsonReader) parseBsonArray(c *ValueCache, value *DxValue) (arrayLen int, err error) {
	//文档长度
	b, err := r.bfReader.Peek(4)
	if err != nil {
		return 0, err
	}
	r.bfReader.Discard(4)
	arrayLen = int(binary.LittleEndian.Uint32(b[:4]))
	parseIndex := 4
	keyName := ""
	//读取元素
	//每个元素为一个类型+字段名+值组成,字段名为数组的索引序号
	var element *DxValue
	for parseIndex < arrayLen {
		b, err = r.bfReader.Peek(1)
		if err != nil {
			return 0, err
		}
		r.bfReader.Discard(1)
		parseIndex++
		//类型
		bType := BsonType(b[0])
		//读取字段,cstring,ansic
		keyName, err = r.bfReader.ReadString(0)
		if err != nil {
			return 0, err
		}
		parseIndex += len(keyName) + 1
		arridx := int(DxCommonLib.StrToIntDef(keyName, -1))
		if arridx == -1 {
			return 0, ErrInvalidArrayBsonIndex
		}
		switch bType {
		case BSON_Array:
			element = value.SetIndexCached(arridx, VT_Array, c)
			arraylen, err := r.parseBsonArray(c, element)
			if err != nil {
				return 0, err
			}
			parseIndex += arraylen
		case BSON_EmbeddedDocument:
			v, doclen, err := r.readDocument(c)
			if err != nil {
				return 0, err
			}
			value.SetIndexValue(arridx, v)
			parseIndex += doclen
		default:
			element = value.SetIndexCached(arridx, VT_NULL, c)
			vlen, err := r.parseValue(bType, element)
			if err != nil {
				return 0, err
			}
			parseIndex += vlen
		}
		if parseIndex == arrayLen-1 && b[parseIndex] == 0 {
			break
		}
	}
	return arrayLen, nil
}

func (r *BsonReader) parseValue(btype BsonType, value *DxValue) (parseIndex int, err error) {
	switch btype {
	case BSON_Double:
		b, err := r.bfReader.Peek(8)
		if err != nil {
			return 0, err
		}
		u64 := binary.LittleEndian.Uint64(b[:8])
		value.SetDouble(*(*float64)(unsafe.Pointer(&u64)))
		r.bfReader.Discard(8)
		return 8, nil
	case BSON_String:
		//UTF8
		b, err := r.bfReader.Peek(4)
		if err != nil {
			return 0, err
		}
		parseIndex = 4
		valueLen := int(binary.LittleEndian.Uint32(b[:4]))
		r.bfReader.Discard(4)
		b, err = r.bfReader.Peek(valueLen)
		if err != nil {
			return 0, err
		}
		parseIndex += valueLen
		//由于会多写一个字符串结束符0，所以，实际长度应该减去1
		value.SetString(string(b[:valueLen-1]))
		r.bfReader.Discard(valueLen)
	case BSON_Binary:
		value.DataType = VT_ExBinary
		value.ExtType = uint8(btype)
		b, err := r.bfReader.Peek(4)
		if err != nil {
			return 0, err
		}
		//先读取长度
		valueLen := int(binary.LittleEndian.Uint32(b[:4]))
		r.bfReader.Discard(4)
		parseIndex = 4

		b, err = r.bfReader.Peek(1)
		if err != nil {
			return 0, err
		}
		//子类型
		subType := b[0]
		if subType == 2 {
			r.bfReader.Discard(1)
			parseIndex++
			b, err = r.bfReader.Peek(4)
			if err != nil {
				return 0, err
			}
			parseIndex += 4
			//再重新处理一遍
			valueLen = int(binary.LittleEndian.Uint32(b[:4]))
			r.bfReader.Discard(4)
			b, err = r.bfReader.Peek(valueLen)
			if err != nil {
				return 0, err
			}
			value.DataType = VT_Binary
			value.ExtType = 0
			value.SetBinary(b[:valueLen], true)
			r.bfReader.Discard(valueLen)
		} else {
			//VT_ExBinary要将subType带上
			valueLen++
			b, err = r.bfReader.Peek(valueLen)
			if err != nil {
				return 0, err
			}
			value.SetBinary(b[:valueLen], true)
			r.bfReader.Discard(valueLen)
		}
		parseIndex += valueLen
	case BSON_Undefined:
	case BSON_ObjectID:
		//12字节
		value.DataType = VT_Binary
		value.ExtType = uint8(btype)
		b, err := r.bfReader.Peek(12)
		if err != nil {
			return 0, err
		}
		value.SetBinary(b[:12], true)
		r.bfReader.Discard(12)
		return 12, nil
	case BSON_Boolean:
		//一个字节
		b, err := r.bfReader.Peek(1)
		if err != nil {
			return 0, err
		}
		r.bfReader.Discard(1)
		if b[0] == 1 {
			value.DataType = VT_True
		} else {
			value.DataType = VT_False
		}
		return 1, nil
	case BSON_DateTime:
		b, err := r.bfReader.Peek(8)
		if err != nil {
			return 0, err
		}
		//Unix 纪元(1970 年 1 月 1 日)以来的毫秒数
		vunix := time.Duration(binary.LittleEndian.Uint64(b[:8])) * time.Millisecond
		value.SetTime(time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC).Add(vunix))
		r.bfReader.Discard(8)
		return 8, nil
	case BSON_Null:
		//啥都不干
	case BSON_Regex:
	case BSON_DBPointer:
	case BSON_JavaScript:
	case BSON_Symbol:
	case BSON_CodeWithScope:
	case BSON_Int32:
		b, err := r.bfReader.Peek(4)
		if err != nil {
			return 0, err
		}
		value.SetInt(int64(binary.LittleEndian.Uint32(b[:4])))
		r.bfReader.Discard(4)
		return 4, nil
	case BSON_Timestamp:
		//64 位值 前4个字节是一个增量，后4个字节是一个时间戳。
		b, err := r.bfReader.Peek(8)
		if err != nil {
			return 0, err
		}
		value.ExtType = uint8(btype)
		value.DataType = VT_Int
		copy(value.simpleV[:], b[:8])
		r.bfReader.Discard(8)
		return 8, nil
	case BSON_Int64:
		b, err := r.bfReader.Peek(8)
		if err != nil {
			return 0, err
		}
		value.SetInt(int64(binary.LittleEndian.Uint64(b[:8])))
		r.bfReader.Discard(8)
		return 8, nil
	case BSON_Decimal128:
		b, err := r.bfReader.Peek(16)
		if err != nil {
			return 0, err
		}
		value.DataType = VT_Binary
		value.ExtType = uint8(btype)
		value.SetBinary(b[:16], true)
		r.bfReader.Discard(16)
		return 16, nil
	case BSON_MinKey:
	case BSON_MaxKey:
	}
	return
}
